package com.apes.fa.service;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.apes.fa.model.*;
import com.apes.fa.respository.FaAssetInventoryItemRepository;
import com.apes.fa.respository.FaAssetInventoryRepository;
import com.apes.fa.respository.FaCardRepository;
import com.apes.fa.respository.FaInventoryProcessTableRepository;
import com.apes.framework.api.DomainService;
import com.apes.framework.jpa.spec.JpaDsl;
import com.apes.framework.jpa.spec.model.Filter;
import com.apes.framework.jpa.spec.model.Group;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.util.Arith;
import com.apes.framework.util.MapUtil;
import com.apes.scm.masterdata.product.model.FaCategory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * @BelongsProject: apes-server
 * @BelongsPackage: com.apes.fa.service
 * @ClassName: FaAssetInventoryService
 * @Author: PengZiFeng
 * @Description: 资产盘点
 * @CreateTime: 2021-09-06 15:38
 * @Version: 1.0
 */
@Service("faAssetInventoryService")
public class FaAssetInventoryService extends DomainService {

    @Autowired
    private FaAssetInventoryRepository faAssetInventoryRepository;
    @Autowired
    private FaAssetInventoryItemRepository faAssetInventoryItemRepository;
    @Autowired
    private FaCardRepository faCardRepository;
    @Autowired
    private FaInventoryProcessTableRepository faInventoryProcessTableRepository;

    /**
     * 保存
     */
    public FaAssetInventory save(SimpleRequest request) {

        FaAssetInventory faAssetInventory = request.getO(FaAssetInventory.class);
        List<FaAssetInventoryItem> faAssetInventoryItems = faAssetInventory.getFaAssetInventoryItems();
        String str = "";
        for (FaCategory faCategory : faAssetInventory.getFaCategories()) {
            str += faCategory.getId() + ",";
        }
        if (faAssetInventoryItems.isEmpty()) {
            throw new RuntimeException("盘点明细不能为空");
        }
        if (!"approve".equals(faAssetInventory.getState())){
            faAssetInventory.setState("create");
            faAssetInventory.setFaCategoryStr(str);
        }
        return faAssetInventoryRepository.saveAndFlush(faAssetInventory);

    }

    /**
     * 删除
     */
    public String delete(SimpleRequest request) {
        FaAssetInventory faAssetInventory = request.getO(FaAssetInventory.class);
        faAssetInventoryRepository.delete(faAssetInventory);
        return "删除成功！";
    }

    /**
     * 审核
     */
    public FaAssetInventory approve(SimpleRequest request) {

        FaAssetInventory faAssetInventory = request.getO(FaAssetInventory.class);
        faAssetInventory.setState("approve");
        faAssetInventory.setApproveDate(new Date());
        faAssetInventory.setApproveUid(this.getPerson(request));
//        List<FaAssetInventoryItem> faAssetInventoryItems = faAssetInventoryItemRepository.findAll(JpaDsl.toCriteriaByEq("faAssetInventory", faAssetInventory, "inventoryProfitQuantity", -1));
//        faAssetInventory.setFaAssetInventoryItems(faAssetInventoryItems);
        return faAssetInventoryRepository.saveAndFlush(faAssetInventory);


    }

    /**
     * 复审生成盘点处理表
     */
    public FaAssetInventory reApprove(SimpleRequest request) {

        FaAssetInventory faAssetInventory = request.getO(FaAssetInventory.class);
        faAssetInventory.setState("reApprove");
        faAssetInventory.setApproveDate(new Date());
        faAssetInventory.setApproveUid(this.getPerson(request));

        FaInventoryProcessTable faInventoryProcessTable = new FaInventoryProcessTable();
        faInventoryProcessTable.setInventoryId(faAssetInventory.getId());
        faInventoryProcessTable.setFaWhereabouts("盘亏");
        faInventoryProcessTable.setBusinessName("(ZCPK)资产盘亏");
        faInventoryProcessTable.setBusinessState("create");
        faInventoryProcessTable.setCompany(faAssetInventory.getCompany());

        //差异的数据
        List<FaInventoryLossCard> faInventoryLossCards = new ArrayList<>();

        for (FaAssetInventoryItem faAssetInventoryItem : faAssetInventory.getFaAssetInventoryItems()) {
            if ((faAssetInventoryItem.getInventoryProfitQuantity() != 0 && faAssetInventoryItem.getReplayQuantity() != 1)
                    || (faAssetInventoryItem.getInventoryProfitQuantity() == 0 && faAssetInventoryItem.getReplayDifference() == -1)) {
                FaInventoryLossCard faInventoryLossCard = new FaInventoryLossCard();
                FaCard faCard = faAssetInventoryItem.getFaCard();

                faCard.setFaStatus("7");
                faInventoryLossCard.setFaCard(faAssetInventoryItem.getFaCard());
                faInventoryLossCard.setProductId(faAssetInventoryItem.getProductId());
                faInventoryLossCard.setProductName(faAssetInventoryItem.getProductName());
                faInventoryLossCard.setAssetWhereabouts("盘亏");
                faInventoryLossCard.setInventoryLossReason("");
                faInventoryLossCard.setUseDepartmentOpinion("");
                faInventoryLossCard.setApproveDepartmentOpinion("");
                //盘亏金额等于 原值减折旧
                double lossAmount = Arith.round(faCard.getOriginalValue() - faCard.getDepreciation(), 2);
                faInventoryLossCard.setLossAmount(lossAmount);
                faInventoryLossCards.add(faInventoryLossCard);
            }

        }
        if (!faInventoryLossCards.isEmpty() || faInventoryLossCards.size() !=0){
            faInventoryProcessTable.setTotalAmount(faInventoryLossCards.stream().mapToDouble(FaInventoryLossCard::getLossAmount).sum());
            faInventoryProcessTable.setFaInventoryLossCards(faInventoryLossCards);
            faInventoryProcessTableRepository.saveAndFlush(faInventoryProcessTable);
        }

//        List<FaAssetInventoryItem> faAssetInventoryItems = faAssetInventoryItemRepository.findAll(JpaDsl.toCriteriaByEq("faAssetInventory", faAssetInventory));
//        faAssetInventory.setFaAssetInventoryItems(faAssetInventoryItems);
        return faAssetInventoryRepository.saveAndFlush(faAssetInventory);

    }

    /**
     * 根据成本中心和资产类别查询资产卡片
     */
    public List<FaAssetInventoryItem> findCard(SimpleRequest request) {

        String deptId = request.get("dept");
        String useDeptId = request.get("useDept");
        List<JSONObject> faCategorys = request.get("faCategoryId");
        List<String> ids = faCategorys.stream().map(faCategory -> faCategory.getString("id")).collect(Collectors.toList());
        List<FaAssetInventoryItem> faAssetInventoryItems = new ArrayList<>();
        Group group = new Group();
        group.setOperator("and");
        if ("".equals(useDeptId)){
            group.addFilters(JpaDsl.toFilter(
                    "dept.id", "EQ", deptId,
                    "state", "EQ", "approve",
                    "faStatus","IN", Arrays.asList("1","2","3","4","7")
            ));
        }else{
            group.addFilters(JpaDsl.toFilter(
                    "useDept.id", "EQ", useDeptId,
                    "state", "EQ", "approve",
                    "faStatus","IN", Arrays.asList("1","2","3","4","7")
            ));
        }

        Group idGroup = new Group();
        idGroup.setOperator("or");
        List<Filter> filters = idGroup.getFilters();
        ids.stream().forEach(id -> {
            Filter filter = new Filter();
            filter.setField("faCategory.id");
            filter.setValue(id);
            filter.setOperator("LIKE");
            filters.add(filter);
        });
        group.addGroup(idGroup);
        List<FaCard> faCards = faCardRepository.findAll(group.build(false));
//        List<FaCard> faCards = faCardRepository.findCardByCostCenterAndCategory(costCenterId, ids);
        if(faCards.isEmpty() && faCards == null) throw new RuntimeException("没有匹配的资产卡片");
        for (FaCard faCard : faCards) {//判空
            FaAssetInventoryItem faAssetInventoryItem = new FaAssetInventoryItem();
            faAssetInventoryItem.setFaCard(faCard);
            faAssetInventoryItem.setProductId(faCard.getProduct().getId());
            faAssetInventoryItem.setProductName(faCard.getProduct().getName());
            faAssetInventoryItem.setCostCenterName(faCard.getDept().getCostCenterId().getName());
            faAssetInventoryItem.setBookQuantity(faCard.getQuantity());
            faAssetInventoryItem.setActualQuantity(1);
            faAssetInventoryItem.setInventoryProfitQuantity(0);
            faAssetInventoryItem.setReplayQuantity(0);
            faAssetInventoryItem.setReplayDifference(0);
            faAssetInventoryItem.setProcessedQuantity(0);
            faAssetInventoryItem.setFaStatus(faCard.getFaStatus());
            faAssetInventoryItems.add(faAssetInventoryItem);
        }
        return faAssetInventoryItems.stream().sorted(Comparator.comparing(FaAssetInventoryItem::getProductId)).collect(Collectors.toList());
    }

    /**
     * 资产盘点导入
     */
    public JSONObject importInfo(SimpleRequest request){
        //Excel信息
        JSONObject importData = request.get("importData");
        JSONArray field = (JSONArray) request.get("data");
        JSONObject exclObject = new JSONObject();                  //返回值

        JSONArray exclArr = new JSONArray();            //行内容
        JSONArray headerName = new JSONArray();         //头部
        JSONArray fieldName = new JSONArray();          //field
        for (Object o : field) {
            JSONObject webTab = (JSONObject) o;
            headerName.add(webTab.get("name"));
            fieldName.add(webTab.get("field"));
        }

        //获取model
        JSONObject model = (JSONObject) request.get("model");
        String deptId = Objects.isNull(model.getJSONObject("dept")) ? "" : model.getJSONObject("dept").getString("id");
        String useDeptId = Objects.isNull(model.getJSONObject("useDept")) ? "" : model.getJSONObject("useDept").getString("id");
        if (Objects.equals(deptId,"") && Objects.equals(useDeptId,"")) throw new RuntimeException("折旧部门和使用部门必须选择一个！！！");
        JSONArray faCategories = Objects.isNull(model.getJSONArray("faCategories")) ? null : model.getJSONArray("faCategories");
        if (Objects.isNull(faCategories)) throw new RuntimeException("固定资产类别代码未选择！！！");

        String state = Objects.isNull(model.getString("state")) ? "create" : model.getString("state");

        request.setData(MapUtil.mapper(
                "dept",deptId,
                "useDept",useDeptId,
                "faCategoryId",faCategories
        ));

        //查询可盘点的资产卡片
        List<FaAssetInventoryItem> cards = findCard(request);

        //归集所有卡片ID
        List<String> cardIds = cards.stream().map(faAssetInventoryItem -> faAssetInventoryItem.getFaCard().getId()).collect(Collectors.toList());

        if (cardIds.size() == 0) return null;

        //业务逻辑
        importData.forEach((k, v) -> {
            //获得value ===Excel内容
            JSONArray excl = (JSONArray) v;
            JSONArray header = (JSONArray) excl.get(0); //首行数据
            for (int i = 0; i < excl.size(); i++) {  //遍历每一行

                if (i == 0) { //跳过首行
                    exclArr.add(headerName);
                    continue;
                }

                JSONArray lineLong = (JSONArray) excl.get(i); //当前行
                if (lineLong.size() == 0) {
                    continue; //跳过空白行
                }
                //合并2个list为一个map,KEY为首行数据，Value为当前行数据
                Map<String, String> rst = IntStream.range(0, header.size()).collect(HashMap::new,
                        (m, key) -> m.put(header.getString(key).replace(";", ""),
                                key >= lineLong.size() ? "" : (lineLong.getString(key) == null ? null : lineLong.getString(key).trim().replaceAll("[\\s]{2,}", " "))),
                        (m1, m2) -> {
                        });


                String faCardId = rst.get("资产卡片编号");

                //判断这张卡片是否存在上面的所有卡片ID中
                if(!cardIds.contains(rst.get("资产卡片编号"))) continue;

                FaCard faCard = faCardRepository.findOne(faCardId);
                //用一个有序的map 封装数据, 防止乱序
                Map<String, Object> map = new LinkedHashMap<>();
                String cpsl = checkNumber(state, rst.get("初盘数量"), "初盘数量");
                String fpsl = checkNumber(state, rst.get("复盘数量"), "复盘数量");
                String cpcy ="0";
                String fpcy ="0";

                if (Objects.equals("create",state) || Objects.equals("approve",state)){
                    cpcy = cpsl.equals("0") ? "-1" : cpsl.equals("1") ? "0" : "0";
                }else if (Objects.equals("reApprove",state)){
                    fpcy = fpsl.equals("0") ? "-1" : fpsl.equals("1") ? "0" : "0";
                }

                map.put("序号", "");
                map.put("资产卡片编号", faCard.getId());
                map.put("商品编号", faCard.getProduct().getId());
                map.put("商品名称", faCard.getProduct().getName());
                map.put("成本中心名称", faCard.getDept().getCostCenterId().getName());
                map.put("账面数量", faCard.getQuantity());
                map.put("初盘数量", cpsl);
                map.put("初盘差异", cpcy);
                map.put("复盘数量", fpsl);
                map.put("复盘差异", fpcy);
                map.put("已处理数量", "0");
                map.put("资产状态", faCard.getFaStatus());
                //将map 转换成 list 利用stream流 引用Map类的getValue方法,弄成一个list
                List<Object> valueList = new ArrayList<>(map.values());
                exclArr.add(valueList);

            }
            exclObject.put(k, exclArr);
        });

        return exclObject;
    }

    public String checkNumber(String state,String value, String field){
        if (Objects.equals("初盘数量",field) && (Objects.equals("create",state) || Objects.equals("approve",state))){
            if (Objects.equals("0",value) || Objects.equals("1",value)){
                return value;
            }else {
                return "0";
            }
        }else if (Objects.equals("复盘数量",field) && Objects.equals("reApprove",state)){
            if (Objects.equals("0",value) || Objects.equals("1",value)){
                return value;
            }else {
                return "0";
            }
        }else {
            return "0";
        }
    }
}
